//
//  GCAlertViewManager.m
//  GCAlertViewDemo
//
//  Created by 贺晓阳 on 2020/10/27.
//

#import "GCAlertViewManager.h"
#import "GCAlertViewTemplate.h"
#import "GCAlertViewFeathers.h"

#pragma mark - 
#pragma mark - Private Item Model

@interface GCAlertViewItem : NSObject

@property (nonatomic, strong, nullable) GCAlertViewFeathers *feathers;//样式model
@property (nonatomic, strong, nullable) GCAlertViewTemplate *alertViewTemplate;//构建实例
@property (nonatomic, assign) NSInteger sn; //serial number 序号

@end

@implementation GCAlertViewItem

- (id)init {
    
    if (self = [super init]) {
        self.feathers = NULL;
        self.alertViewTemplate = NULL;
        self.sn = -1;
    }
    return self;
}

@end

#pragma mark -
#pragma mark - GCAlertViewManager

@interface GCAlertViewManager()

typedef void(^GetAlertViewItemComplete)( GCAlertViewItem * _Nullable alertViewItem);

@property(nonatomic, strong) dispatch_queue_t dispatch_serial; //串行队列
@property(nonatomic, strong) NSMutableArray<GCAlertViewItem *> *maxHeap; //弹窗堆
@property(nonatomic, assign) NSInteger accumulateCount; //会话内累计弹框数

@property(nonatomic, strong, nullable) GCAlertViewItem *currentShowItem;//当前展示的alertView

@end

@implementation GCAlertViewManager

+ (instancetype)sharedAlertViewManager {
    
    static GCAlertViewManager *manager = nil;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        manager = [[GCAlertViewManager alloc] init];
        manager.dispatch_serial = dispatch_queue_create("com.gluecomponents.alert", DISPATCH_QUEUE_SERIAL);
        manager.maxHeap = [NSMutableArray arrayWithCapacity:0];
        manager.accumulateCount = 0;
        manager.currentShowItem = NULL;
    });
    return manager;
}

/// 堆中插入一个新条目
/// @param alertViewFeathers 新条目
- (void)insertAletViewItem:(GCAlertViewFeathers *)alertViewFeathers {
    
    dispatch_async(self.dispatch_serial, ^{
        
        GCAlertViewItem *alertViewItem = [[GCAlertViewItem alloc] init];
        alertViewItem.feathers = alertViewFeathers;
        alertViewItem.sn = ++self.accumulateCount;
        [self.maxHeap addObject:alertViewItem];
        [self shiftUpItemAtIndex:self.maxHeap.count-1];
        if (alertViewItem.feathers.weight >= self.currentShowItem.feathers.weight) {
            [self showAlertViewByComprehensiveWeight];
        }
    });
}

#pragma mark - AlertView-Manual Private Methods

///通过综合权重展示alertView
- (void)showAlertViewByComprehensiveWeight {
    
    GCAlertViewItem *showItem = [self getMaxComprehensiveWeightAletViewItem];
    NSLog(@"获取栈顶:%@ %ld",showItem, (long)showItem.feathers.weight);
    NSLog(@"self.currentShowItem:%@ %ld",self.currentShowItem, (long)self.currentShowItem.feathers.weight);
    if (showItem == self.currentShowItem) {
        return;
    }
    
    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    dispatch_async(dispatch_get_main_queue(), ^{
        if (self.currentShowItem) {
            NSLog(@"self.currentShowItem将消失:%@ %ld 配置其不能点击",self.currentShowItem, (long)self.currentShowItem.feathers.weight);
            self.currentShowItem.alertViewTemplate.alertView.userInteractionEnabled = NO;
            [self.currentShowItem.alertViewTemplate dismiss];
        }
        [self showAlertViewByItem:showItem];
        dispatch_semaphore_signal(sem);
    });
    //在主线程执行alert show的h过程中会更新currentShowItem，所以这里需要等待主线程执行完毕
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
}

- (void)showAlertViewByItem:(GCAlertViewItem *)item {
    
    if (!item) {
        return;
    }
    
    self.currentShowItem = item;

    NSLog(@"item将展示:%@ %ld",item, (long)item.feathers.weight);

    GCAlertViewTemplate *alertTemplate = [[GCAlertViewTemplate alloc] init];
    
    [alertTemplate buildGCAlertView:item.feathers];
        
    for (int i = 0; i < item.feathers.buttonTitles.count; i++) {
        
        UIColor *defaultColor = [UIColor blueColor];
        
        if (i < item.feathers.buttonTitleColors.count) {
            defaultColor = item.feathers.buttonTitleColors[i];
        }
        UIFont *defaultFont = [UIFont systemFontOfSize:18];
        [alertTemplate addAction:item.feathers.buttonTitles[i] color:defaultColor font:defaultFont click:^{
            NSLog(@"%ld能否点击:%d ",(long)item.feathers.weight ,item.alertViewTemplate.alertView.userInteractionEnabled);
                if (!item.alertViewTemplate.alertView.userInteractionEnabled) {
                    return;
                }
                item.alertViewTemplate = NULL;
                //点击事件回调
                if (item.feathers.alertViewClicked){
                    NSLog(@"权重:%ld sn:%ld 将消失",(long)item.feathers.weight,(long)item.sn);
                    item.feathers.alertViewClicked(i);
                    item.feathers.alertViewClicked = nil;
                }
                dispatch_semaphore_t sem = dispatch_semaphore_create(0);
                [self deleteAletViewItemBySN:item.sn complete:^(GCAlertViewItem * _Nullable alertViewItem) {
                    if (alertViewItem.feathers.clearOther) {
                        NSLog(@"清空。。。。。。。。。。");
                        [self.maxHeap removeAllObjects];
                    }
                    self.currentShowItem = NULL;
                    dispatch_semaphore_signal(sem);
                    [self showAlertViewByComprehensiveWeight];
                }];
                //等待堆维护结束后再执行dismiss，参见GCAlertView.m -[GCAlertView btnAction:]，避免快速点击出现问题
                dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
        }];
    }
    [alertTemplate show];
    item.alertViewTemplate = alertTemplate;
}

#pragma mark - Heap-Manual Private Methods

/// 抽取出综合权重最大的alertViewItem 并不从堆中删除
- (GCAlertViewItem *)getMaxComprehensiveWeightAletViewItem {
    return self.maxHeap.firstObject;
}

/// 根据sn值删除alertViewItem
/// @param sn 序列号
- (void)deleteAletViewItemBySN:(NSInteger)sn complete:(GetAlertViewItemComplete)getAlertViewItemComplete {
    
    dispatch_async(self.dispatch_serial, ^{
        
        GCAlertViewItem *targetItem = NULL;
        
        for (NSInteger i=0; i<self.maxHeap.count; i++) {
            
            if (((GCAlertViewItem *)self.maxHeap[i]).sn == sn) {
                targetItem = self.maxHeap[i];
                self.maxHeap[i] = self.maxHeap[self.maxHeap.count-1];
                [self.maxHeap removeLastObject];
                [self shiftDownItemAtIndex:i];
                break;
            }
        }
        
        if (getAlertViewItemComplete) {
            getAlertViewItemComplete(targetItem);
        }
    });
}

/// shiftUp方法
/// @param index 执行索引
- (void)shiftUpItemAtIndex:(NSInteger)index {
    
    if (index < 1) {
        return;
    }
    
    if (![self isValid:index]) return;
    
    NSInteger father = (index-1)/2;
    if (![self isValid:father]) return;
    
    NSInteger maxIndex = [self getMaxIndexByWeightAndSNBetween:index bIndex:father];
    if (index == maxIndex) {
        [self swapItemAtIndex:index bIndex:father];
        [self shiftUpItemAtIndex:father];
    }
}

/// shiftDown方法
/// @param index 执行索引
- (void)shiftDownItemAtIndex:(NSInteger)index{

    if (![self isValid:index]) return;
    
    NSInteger left = 2*index + 1;
    NSInteger right = 2*index + 2;
    if (![self isValid:left] && ![self isValid:right]) return;
    
    NSInteger maxIndex = [self getMaxIndexByWeightAndSNBetween:left bIndex:right];
    maxIndex = [self getMaxIndexByWeightAndSNBetween:maxIndex bIndex:index];
    
    if (index != maxIndex) {
        [self swapItemAtIndex:index bIndex:maxIndex];
        [self shiftDownItemAtIndex:maxIndex];
    }
}

/// 判断索引在堆中是否有效
/// @param index 待判断的索引
- (BOOL)isValid:(NSInteger)index {
    
    if (index<self.maxHeap.count && index>=0) {
        return YES;
    }
    return NO;
}

/// 比较两索引指向的alertViewItem，根据权重值和序号，返回综合权重最大的索引
/// 具体规则：当weight值不同时，返回weight值最大的；当weight值相同时，返回序号最大的（最后入堆的）
/// @param aIndex 索引a
/// @param bIndex 索引b
- (NSInteger)getMaxIndexByWeightAndSNBetween:(NSInteger)aIndex bIndex:(NSInteger)bIndex {
    
    if (![self isValid:aIndex] && ![self isValid:bIndex]) {
        return -1;
    }else if(![self isValid:aIndex]){
        return bIndex;
    }else if(![self isValid:bIndex]){
        return aIndex;
    }
    
    GCAlertViewItem *aItem = self.maxHeap[aIndex];
    GCAlertViewItem *bItem = self.maxHeap[bIndex];

    if (aItem.feathers.weight == bItem.feathers.weight) {
        return (aItem.sn>bItem.sn) ? aIndex : bIndex;;
    }
    
    return (aItem.feathers.weight>bItem.feathers.weight) ? aIndex : bIndex;
}

/// 交换两索引指向的alertViewItem在堆中的位置
/// @param aIndex 索引a
/// @param bIndex 索引b
- (void)swapItemAtIndex:(NSInteger)aIndex bIndex:(NSInteger)bIndex{
    
    if (aIndex>=self.maxHeap.count || bIndex>=self.maxHeap.count) {
        NSLog(@"GC-swapItemAtIndex-数组越界，无法交换!");
        return;
    }
    
    GCAlertViewItem *tempItem = self.maxHeap[aIndex];
    self.maxHeap[aIndex] = self.maxHeap[bIndex];
    self.maxHeap[bIndex] = tempItem;
}

#pragma mark - Test Methods

- (void)checkHeap {
    
    dispatch_async(self.dispatch_serial, ^{
        NSString *str = @"[";
        for (int i = 0; i < self.maxHeap.count; i++) {
            NSInteger current = self.maxHeap[i].feathers.weight;
            str = [str stringByAppendingString:[NSString stringWithFormat:@"%ld, ",(long)self.maxHeap[i].feathers.weight]];

            if (2*i+2<self.maxHeap.count) {
                NSInteger left = self.maxHeap[i*2+2].feathers.weight;
                if (current < left) {
                    NSLog(@"%ld位置错误",(long)current);
                }
            }
            if (2*i+1<self.maxHeap.count) {
                NSInteger right = self.maxHeap[i*2+1].feathers.weight;
                if (current < right) {
                    NSLog(@"%ld位置错误",(long)current);
                }
            }
        }
        str = [str stringByAppendingString:@"]"];
        NSLog(@"%@",str);
    });
}

@end
